package com.zhou.core.scheduler;

import com.alibaba.fastjson.JSON;
import com.zhou.core.esb.common.Const;
import com.zhou.core.scheduler.job.AbstractJob;
import com.zhou.util.TimeUtils;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

/**
 * 游戏调度器
 * Created by zhouyongjun on 2020/8/26
 */

@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class GameJobScheduler  {
    Scheduler scheduler;
    private final static Logger log = LoggerFactory.getLogger(GameJobScheduler.class);


    public void init() throws Exception {
        scheduler = StdSchedulerFactory.getDefaultScheduler();
    }


    public void startup() throws Exception {
       scheduler.start();
    }


    public void shutdown() throws Exception {
        scheduler.shutdown();
    }

    /**
     * 执行一次job
     * @param jobClass class
     * @param jobName
     * @param delay 执行延迟时间
     * @param timeUnit 延迟单位
     * @param extraObjects job 执行时额外参数
     */
    public void addeJob(Class<? extends Job> jobClass, String jobName,long delay, TimeUnit timeUnit, Object... extraObjects) {
        //创建触发器
        try {
            Trigger trigger = null;
            TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger().withIdentity(jobName,jobName)
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule());
            if (timeUnit != null)
            {
                Date delayDate = TimeUtils.now().plusMillis((int) timeUnit.toMillis(delay)).toDate();
                triggerBuilder.startAt(delayDate);
            }else
            {
                triggerBuilder.startNow();
            }
            trigger = triggerBuilder.build();
            //创建任务
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName,jobName)
                    .build();
            //传入调度的数据，在Job中需要使用
            if (extraObjects != null && extraObjects.length > 0)
            {
                jobDetail.getJobDataMap().put(Const.SCHEDULER_EXTRA_JOB_OBJECTS,extraObjects);
            }
            //调度作业
            Date date = scheduler.scheduleJob(jobDetail,trigger);
            log.info("addJob  jobClass={},jobName={},delay={},timeUnit={},date={},extraObjects={}",jobClass,jobName,delay,timeUnit, TimeUtils.formatChDateTime(date.getTime()),JSON.toJSONString(extraObjects));
        } catch (Exception e) {
            log.error("error ",e);
        }
    }
    public void addeJob(Class<? extends AbstractJob> jobClass) {
        //创建触发器
        addeJob(jobClass,jobClass.getSimpleName(),0,null);
    }

    /**
     * 立刻执行
     * @param jobClass
     * @param extraObjects job需要参数
     */
    public void addeJob(Class<? extends AbstractJob> jobClass, Object[] extraObjects) {
        //创建触发器
        addeJob(jobClass,jobClass.getSimpleName(),0,null,extraObjects);
    }


    public void addCronJob(Class<? extends AbstractJob> jobClass,String cronString) {
        addCronJob(jobClass,cronString,null);
    }

    public void addCronJob(Class<? extends AbstractJob> jobClass,String cronString,Object[] extraObjects) {
        addCronJob(jobClass,jobClass.getSimpleName(),cronString,0,null,null,extraObjects);
    }

    public void addCronJob(Class<? extends AbstractJob> jobClass,String cronString,long delay, TimeUnit timeUnit) {
        addCronJob(jobClass,jobClass.getSimpleName(),cronString,delay,timeUnit,null);
    }

    public void addCronJob(Class<? extends AbstractJob> jobClass,String cronString,long delay, TimeUnit timeUnit,Object[] extraObjects) {
      addCronJob(jobClass,jobClass.getSimpleName(),cronString,delay,timeUnit,null,extraObjects);
    }

    /**
     * 表达式执行
     * @param jobClass
     * @param jobName job名字
     * @param cronString 表达式格式  在线生成表达式网址：https://qqe2.com/cron
     * @param timeZone 时区,null使用本机时区
     * @param extraObjects job需要参数
     */
    public void addCronJob(Class<? extends Job> jobClass,String jobName,String cronString,long delay, TimeUnit timeUnit,TimeZone timeZone,Object... extraObjects) {
        //创建触发器
        try {
            CronExpression cronExpression = new CronExpression(cronString);
//            TimeZone zone = TimeZone.getDefault();
//            try {
//                if (!StringUtils.isEmpty(timeZone))
//                {
//                    zone = TimeZone.getTimeZone(timeZone);
//                }
//            } catch (Exception e) {
//                log.error(" error :  timeZone = " + timeZone,e);
//            }
            if (timeZone != null)
            {
                cronExpression.setTimeZone(timeZone);
            }
            TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger().withIdentity(jobName)
                    .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression));
            if (timeUnit != null)
            {
                Date delayDate = TimeUtils.now().plusMillis((int) timeUnit.toMillis(delay)).toDate();
                triggerBuilder.startAt(delayDate);
            }else
            {
                triggerBuilder.startNow();
            }
            Trigger trigger = triggerBuilder.build();
            //创建任务
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName)
                    .build();
            //传入调度的数据，在Job中需要使用
            if (extraObjects != null && extraObjects.length > 0)
            {
                jobDetail.getJobDataMap().put(Const.SCHEDULER_EXTRA_JOB_OBJECTS,extraObjects);
            }
            //调度作业
            Date date = scheduler.scheduleJob(jobDetail,trigger);
            log.info("addCronJob  jobClass={},jobName={},cronString={},date={},timeZone={},extraObjects={}",jobClass,jobName,cronString,TimeUtils.formatChDateTime(date.getTime()),cronExpression.getTimeZone().getID(), JSON.toJSONString(extraObjects));
        } catch (Exception e) {
            log.error("error ",e);
        }
    }
}
